/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using NDODS.DAP.BaseTypes;
using NDODS.DAP.Exceptions;

namespace NDODS.DAP.Server
{
    /// <summary> Represents a source of Clause objects for the constraint expression
    /// parser.  By inheriting from this class and overriding the "newX" methods,
    /// you can create a factory that provides your own Clause objects instead
    /// of the default ones. This custom factory can be given to the parser
    /// via the CEEvaluator interface.
    /// 
    /// </summary>
    /// <seealso cref="CEEvaluator">
    /// </seealso>
    public class ClauseFactory
    {
        /// <summary> Creates a new clause factory with a blank function library. This
        /// constructor is sufficient for servers with no server side functions.
        /// 
        /// </summary>
        /// <seealso cref="FunctionLibrary">
        /// </seealso>
        public ClauseFactory() {
            this.functionLibrary = new FunctionLibrary();
        }

        /// <summary> Creates a clause factory which uses the specified function library.
        /// This constructor allows you to parse CE's using a customized function
        /// library.
        /// 
        /// </summary>
        /// <param name="functionLibrary">The function library that will be used
        /// when creating clauses that invoke server-side functions.
        /// </param>
        public ClauseFactory(FunctionLibrary functionLibrary) {
            this.functionLibrary = functionLibrary;
        }

        /// <summary> Generates a clause which which compares subclauses, using one of the
        /// relative operators supported by the Operator class.
        /// </summary>
        public virtual ITopLevelClause newRelOpClause(int operator_Renamed, ISubClause lhs, IList rhs) {
            return new RelOpClause(operator_Renamed, lhs, rhs);
        }

        /// <summary> Generates a clause which invokes a function that returns a
        /// bool value.
        /// 
        /// </summary>
        /// <seealso cref="BoolFunctionClause">
        /// </seealso>
        public virtual ITopLevelClause newBoolFunctionClause(String functionName, IList children) {
            BoolFunction function = functionLibrary.getBoolFunction(functionName);
            if (function == null) {
                if (functionLibrary.getBTFunction(functionName) != null) {
                    throw new NoSuchFunctionException("The function " + functionName + "() does not return a " +
                                                      "bool value, and must be used in a comparison or " +
                                                      "as an argument to another function.");
                }
                else {
                    throw new NoSuchFunctionException("This server does not support a " + functionName + "() function");
                }
            }
            return new BoolFunctionClause(function, children);
        }

        /// <summary> Generates a clause representing a simple value,
        /// such as "var1" or "19".
        /// 
        /// </summary>
        /// <seealso cref="ValueClause">
        /// </seealso>
        public virtual ISubClause newValueClause(BaseType value_Renamed, bool constant) {
            return new ValueClause(value_Renamed, constant);
        }

        /// <summary> Generates a clause which invokes a function that returns a
        /// BaseType.
        /// 
        /// </summary>
        /// <seealso cref="BTFunctionClause">
        /// </seealso>
        public virtual ISubClause newBTFunctionClause(String functionName, IList children) {
            BTFunction function = functionLibrary.getBTFunction(functionName);
            if (function == null) {
                if (functionLibrary.getBoolFunction(functionName) != null) {
                    throw new NoSuchFunctionException("The function " + functionName + "() cannot be used as a " +
                                                      "sub-expression in a constraint clause");
                }
                else {
                    throw new NoSuchFunctionException("This server does not support a " + functionName + "() function");
                }
            }
            return new BTFunctionClause(function, children);
        }

        /// <summary> Generates a clause representing a remote value, referenced by a URL.
        /// Note that dereferencing is not currently supported, and the default
        /// implementation of this clause type throws an exception when it is
        /// evaluated.
        /// 
        /// </summary>
        /// <seealso cref="DereferenceClause">
        /// </seealso>
        public virtual ISubClause newDereferenceClause(String url) {
            return new DereferenceClause(url);
        }

        protected internal FunctionLibrary functionLibrary;
    }
}